/**
 * i18n function of libdragonscript
 * Copyright (C) 2009 Hajime Yoshimori <RoarLudros@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "IntlCommon"
#include "DragonExcept"
#include "DragonMessage"
#include "ErrnoMessage"

#include <cstdlib>
#include <string>
#include <cstring>
#include <wchar.h>
#include <iconv.h>
#include <cerrno>

#include <libintl.h>


#include <config.h>

using namespace std;

namespace dragon {

  #define _(msg) (msg)

  const DragonMessage msgDomainNotFound
  = DragonMessage(DragonMessage::error,
				  _("Such domain name is not registered. (normal)"),
				  _("Such domain name is not registered. (dragon)"));

  #undef _
}

void dragon::IntlCommon::addDomain(const char* name) {
  std::string a = name;
  bindtextdomain(name, MO_INSTALL_PATH);
  _domain_list.insert(a);
}

dragon::IntlCommon::domain_list::iterator dragon::IntlCommon::getDomain(const char* name) {
  domain_list::iterator p = _domain_list.find(std::string(name));
  if(p != _domain_list.end()) {
	return p;
  } else {
	throw DragonExcept(&msgDomainNotFound);
  }
}

void dragon::IntlCommon::delDomain(const char* name) {
  domain_list::iterator p = _domain_list.find(name);
  if(p != _domain_list.end()) {
	_domain_list.erase(p);
  }
}

void dragon::IntlCommon::delDomain(domain_list::iterator p) {
  _domain_list.erase(p);
}

std::string& dragon::IntlCommon::wcstombs(const std::wstring& wstr) {
  static string ret;
  ret = "";	// reset the string.
  
  mbstate_t mbs;
  memset(&mbs, 0, sizeof(mbs));	// Initialize.
  
  char *tmp = new char[MB_CUR_MAX + 1];	// multibyte char.
  
  const wchar_t *cur = wstr.c_str();	// pointer to converting char.
  size_t count;
  
  while(*cur != L'\0') {
	errno = 0;
	count = wcrtomb(tmp, *cur, &mbs);
	if(errno != 0) {
	  static ErrnoMessage t(errno);
	  throw DragonExcept(&t);
	}
	tmp[count] = '\0';
	ret += tmp;
	cur++;
  }

  delete [] tmp;
  return ret;
}

std::wstring& dragon::IntlCommon::mbstowcs(const std::string& str) {
  static wstring ret;
  ret = L"";	// reset the string.
  
  mbstate_t mbs;
  memset(&mbs, 0, sizeof(mbs));	// Initialize.
  
  wchar_t tmp;	// wide-char.
  const char *cur = str.c_str();	// pointer to converting char.
  const char *last = str.c_str() + str.length();
  size_t count;
  
  while(*cur != '\0' && cur <= last) {
	errno = 0;
	count = mbrtowc(&tmp, cur, last - cur, &mbs);
	if(errno != 0) {
	  static ErrnoMessage t(errno);
	  throw DragonExcept(&t);
	} else if(count == (size_t)-2) {
	  throw DragonExcept(&msgCharConvError);
	}
	ret += tmp;
	cur += count;
  }
  
  return ret;
}


// 	
// 	string& convert(iconv_t context, const std::string& from) {
// 	  const size_t bufsize = 1024;	// buffer size for converting
// 	  
// 	  static string ret;
// 	  char *const outstart = new char[bufsize];
// 	  char *outptr         = outstart;
// 	  char *const instart  = new char[bufsize];
// 	  char *inptr          = instart;
// 	  const char *fromcur  = from.c_str();
// 	  const char *const fromend = fromcur + from.length();
// 	  
// 	  size_t inleft;
// 	  size_t outleft;
// 	  
// 	  ret = "";
// 	  
// 	  while(fromcur < fromend) {
// 		memset(outstart, 0, bufsize);
// 		strncpy(instart, fromcur, bufsize);
// 		*(instart + bufsize) = '\0';
// 		
// 		inptr  = instart;
// 		outptr = outstart;
// 		inleft  = bufsize; 
// 		outleft = bufsize;
// 		
// 		errno = 0;
// 		size_t s = iconv(context, &inptr, &inleft, &outptr, &outleft);
// 		if(s == (size_t)-1 && errno == EILSEQ) {
// 		  throw dragon::DragonExcept(&msgCharConvError);
// 		  
// 		} else if(s == (size_t)-1 && errno == EINVAL) {
// 		  if(inptr - instart == 0) {
// 			throw dragon::DragonExcept(&msgCharConvError);
// 		  }
// 		} else if(s == (size_t)-1 && errno == E2BIG) {
// 		  if(inptr - instart == 0) {
// 			throw dragon::DragonExcept(&msgCharConvError);
// 		  }
// 		}
// 		
// 		fromcur += inptr - instart;
// 		ret += outstart;
// 	  }
// 	  
// 	  delete [] outstart;
// 	  return ret;
// 	}
// 	
// 	std::string& convert(const std::string& from_code, 
// 						 const std::string& to_code, 
// 						 const std::string& from) {
// 	  static string ret;
// 	  iconv_t cd = iconv_open(to_code.c_str(), from_code.c_str());
// 	  ret = convert(cd, from);
// 	  iconv_close(cd);
// 	  return ret;
// 	}
//   };
// };

